home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / quicktimeintro / sequence grabbing / completed lab / sequencegrab.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-06  |  10.6 KB  |  415 lines

  1. /*    Sequence Grabber Lab
  2.  
  3.     This sample shows how to use a sequence grabber component to preview and record captured data.
  4.     The example also demonstrates how to set up VideoBottlenecks and draw over top of captured data
  5.     during the GrabFrameComplete callback.
  6. */
  7.     
  8. #include "SequenceGrab.h"
  9.  
  10. // globals
  11. // ------------------------
  12. BitMap screenBits;
  13. ICMAlignmentProcRecord    apr;
  14.  
  15. // functions
  16. // ------------------------
  17.  
  18. // GrabFrameCompleteProc
  19. // This is where we draw text over the captured frame
  20. pascal ComponentResult GrabFrameCompleteProc(SGChannel sgChan, short nBufferNum, Boolean *pbDone, long lRefCon)
  21. {
  22.     ComponentResult        err = noErr;
  23.     
  24.     // call the default grab-complete function
  25.      err = SGGrabFrameComplete(sgChan,        // channel reference
  26.                                nBufferNum,    // buffer identifier, provided for you
  27.                                pbDone);        // pointer to a boolean, has the frame been completely captured? provided for you
  28.      
  29.      // if the frame is done, draw some text over it
  30.     if (*pbDone) {
  31.         CGrafPtr        pOldPort;
  32.         CGrafPtr        pTempPort = (CGrafPtr)lRefCon;
  33.         GDHandle        hghOldDevice;
  34.         PixMapHandle    hPixMap, hOldPixMap;
  35.         Rect            rectBuffer;
  36.  
  37.         // set to our temporary port
  38.         GetGWorld(&pOldPort, &hghOldDevice);
  39.         SetGWorld(pTempPort, NULL);
  40.  
  41.         // obtain information about a buffer that has
  42.         // been passed to your callback function
  43.         err = SGGetBufferInfo(sgChan,        // channel reference
  44.                               nBufferNum,    // buffer identifier, the sg component provides this value to your callback function.
  45.                               &hPixMap,        // pointer to a location to receive a handle to the pixel map that contains the image.
  46.                               &rectBuffer,    // rectangle structure that is to receive the dimensions of the image’s boundary rectangle.
  47.                               NULL,            // pointer to filter buffer, NULL for no buffer
  48.                               NULL);        // filter buffer rect
  49.         
  50.         if (err == noErr) {
  51.             // set up to draw into this buffer
  52.             hOldPixMap = GetPortPixMap(pTempPort);
  53.             SetPortPix(hPixMap);
  54.  
  55.             // draw some text into the buffer
  56.             TextSize(10);
  57.             TextMode(srcXor);
  58.             MoveTo(rectBuffer.left + 5, rectBuffer.bottom - 5);
  59.             DrawString("\pGrabFrameCompleteProc");
  60.             
  61.             // restore temporary port
  62.             SetPortPix(hOldPixMap);
  63.         }
  64.  
  65.         // restore old ports
  66.         SetGWorld(pOldPort, hghOldDevice);
  67.     }
  68.     
  69.     return err;
  70. }
  71.  
  72. // SetupVideoBottlenecks
  73. // This function initializes the video bottleneck procedure so the sequence grabber
  74. // will call us when a frame has been captured. There are nine bottleneck procs.
  75. /*         struct VideoBottles {
  76.             short                           procCount;
  77.             SGGrabBottleUPP                 grabProc;
  78.             SGGrabCompleteBottleUPP         grabCompleteProc;
  79.             SGDisplayBottleUPP              displayProc;
  80.             SGCompressBottleUPP             compressProc;
  81.             SGCompressCompleteBottleUPP     compressCompleteProc;
  82.             SGAddFrameBottleUPP             addFrameProc;
  83.             SGTransferFrameBottleUPP        transferFrameProc;
  84.             SGGrabCompressCompleteBottleUPP  grabCompressCompleteProc;
  85.             SGDisplayCompressBottleUPP      displayCompressProc;
  86.         }
  87. */
  88. OSErr SetupVideoBottlenecks(SGChannel sgchanVideo, CGrafPtr pTempPort)
  89. {
  90.     OSErr    err = noErr;
  91.  
  92.     // set the value of a reference constant that is passed to the callback functions
  93.     err = SGSetChannelRefCon(sgchanVideo, (long)pTempPort);
  94.     
  95.     if (err == noErr) {
  96.         VideoBottles    vb;
  97.  
  98.         // get the current bottlenecks
  99.         vb.procCount = 9;
  100.         err = SGGetVideoBottlenecks(sgchanVideo, &vb);
  101.         
  102.         if (err == noErr) {
  103.             RgnHandle    theRgn = NewRgn();
  104.             
  105.             // add our GrabFrameComplete function
  106.             vb.grabCompleteProc = NewSGGrabCompleteBottleUPP(GrabFrameCompleteProc);
  107.             err = SGSetVideoBottlenecks(sgchanVideo, &vb);
  108.             
  109.             // set up the temporary port with
  110.             // a wide open visible and clip region...
  111.             // so that you can use it in any video buffer
  112.             SetRectRgn(theRgn, -32000, -32000, 32000, 32000);
  113.             SetPortVisibleRegion(pTempPort, theRgn);
  114.             SetPortClipRegion(pTempPort, theRgn);
  115.             
  116.             // tell QuickDraw about the changes
  117.             PortChanged((GrafPtr)pTempPort);
  118.             
  119.             DisposeRgn(theRgn);
  120.         }
  121.     }
  122.  
  123.     return err;
  124. }
  125.  
  126. // MakeSequenceGrabber
  127. // Open the default sequence graber component and initialize it
  128. SeqGrabComponent MakeSequenceGrabber(WindowPtr pMacWnd)
  129. {
  130.     SeqGrabComponent    seqGrab = NULL;
  131.     long                flags = 0;
  132.     OSErr                err = noErr;
  133.  
  134.     // open up the default sequence grabber
  135.     seqGrab = OpenDefaultComponent(SeqGrabComponentType, 0);
  136.     
  137.     if (seqGrab != NULL) { 
  138.         // initialize the default sequence grabber component
  139.         err = SGInitialize(seqGrab);
  140.  
  141.         if (err == noErr) {
  142.             // get and set the sequence grabber control flags
  143.             SGGetFlags(seqGrab, &flags);
  144.             //flags |= sgFlagAllowNonRGBPixMaps;
  145.             SGSetFlags(seqGrab, flags);
  146.             
  147.             // set the graphics world to the specified window
  148.             err = SGSetGWorld(seqGrab, GetWindowPort(pMacWnd), NULL);
  149.             
  150.             // get the default sequence grabber drag aligned proc
  151.             SGGetAlignmentProc(seqGrab, &apr);
  152.         }
  153.     }
  154.  
  155.     if (err && (seqGrab != NULL)) {
  156.         // clean up on failure
  157.         CloseComponent(seqGrab);
  158.         seqGrab = NULL;
  159.     }
  160.     return seqGrab;
  161. }
  162.  
  163. // MakeSequenceGrabChannels
  164. // Create the new video and sound channels and set up the channel usage
  165. void MakeSequenceGrabChannels(SeqGrabComponent seqGrab, SGChannel *sgchanVideo, SGChannel *sgchanSound, const Rect *rect, Boolean bWillRecord)
  166. {
  167.     long    lUsage;
  168.     
  169.     OSErr    err = noErr;
  170.  
  171.     // figure out the channel usage
  172.     lUsage = seqGrabPreview;        // always previewing by default
  173.     if (bWillRecord)
  174.         lUsage |= seqGrabRecord;    // are we going to record?
  175.  
  176.     // create a video channel
  177.     err = SGNewChannel(seqGrab, VideoMediaType, sgchanVideo);
  178.     if (err == noErr) {
  179.         // set boundaries for new video channel
  180.         err = SGSetChannelBounds(*sgchanVideo, rect);
  181.         
  182.         // set usage for new video channel
  183.         if (err == noErr)
  184.             err = SGSetChannelUsage(*sgchanVideo, lUsage | seqGrabPlayDuringRecord);
  185.         
  186.         if (err != noErr) {
  187.             // clean up on failure
  188.             SGDisposeChannel(seqGrab, *sgchanVideo);
  189.             *sgchanVideo = NULL;
  190.         }
  191.     }
  192.  
  193.     // create a sound channel
  194.     err = SGNewChannel(seqGrab, SoundMediaType, sgchanSound);
  195.     if (err == noErr) {
  196.         // set usage of new sound channel
  197.         err = SGSetChannelUsage(*sgchanSound, lUsage);
  198.         
  199.         if (err != noErr) {
  200.             // clean up on failure
  201.             SGDisposeChannel(seqGrab, *sgchanSound);
  202.             *sgchanSound = NULL;
  203.         }
  204.     }
  205. }
  206.  
  207. OSErr DoRecord(SeqGrabComponent seqGrab)
  208. {
  209.     FSSpec    theFSSpec;
  210.     Boolean isSelected, isReplacing;
  211.     OSErr                err = noErr;
  212.     
  213.     // Stop everything while the dialogs are up
  214.     SGStop(seqGrab);
  215.     
  216.     err = PutFile("\pSave new movie file as:", "\pSequenceGrab.mov", &theFSSpec, &isSelected, &isReplacing);
  217.     if ((err = SGSetDataOutput(seqGrab, &theFSSpec, seqGrabToDisk)))
  218.         goto bail;
  219.         
  220.     // Attempt to recover the preview area obscured by dialogs
  221.     SGUpdate(seqGrab, 0);
  222.  
  223.     // Make the movie file
  224.     DeleteMovieFile(&theFSSpec);
  225.     err = CreateMovieFile(&theFSSpec, sigMoviePlayer, smSystemScript,
  226.                          createMovieFileDontOpenFile |
  227.                          createMovieFileDontCreateMovie |
  228.                          createMovieFileDontCreateResFile,
  229.                          nil,
  230.                          nil);
  231.     if (err) goto bail;
  232.         
  233.     FlushEvents(mDownMask+mUpMask,0);
  234.     
  235.     // Record!
  236.     err = SGStartRecord(seqGrab);
  237.     if (err) goto bail;
  238.  
  239.     while (!Button() && (err == noErr))
  240.     {
  241.         err = SGIdle(seqGrab);
  242.     }
  243.     
  244.     FlushEvents(mDownMask+mUpMask,0);
  245.  
  246.     // If we recorded until we ran out of space, then allow SGStop to be
  247.     // called to write the movie resource.  The assumption here is that the
  248.     // data output filled up but the disk has enough free space left to
  249.     // write the movie resource.
  250.     if (!((err == dskFulErr) || (err != eofErr))) {
  251.         DeleteMovieFile(&theFSSpec);
  252.         goto bail;
  253.     }
  254.         
  255.     err = SGStop(seqGrab);
  256.  
  257. bail:    
  258.     
  259.     err = SGStartPreview(seqGrab);
  260.  
  261.     return err;
  262. }
  263.  
  264. WindowRef MakeAWindow(void)
  265. {
  266.     WindowPtr        pMacWnd;
  267.     Rect            rectWnd = {0, 0, 230, 320};
  268.     Rect            rectBest;
  269.  
  270.     // figure out the best monitor for the window
  271.     GetBestDeviceRect(NULL, &rectBest);
  272.  
  273.     // put the window in the top left corner of that monitor
  274.     OffsetRect(&rectWnd, rectBest.left + 10, rectBest.top + 50);
  275.  
  276.     // create the window
  277.     pMacWnd = NewCWindow(NULL, &rectWnd, "\pSequence Grabber",true, kWindowDocumentProc, (WindowPtr)-1,true, 0);
  278.  
  279.     // set the port to the new window
  280.     SetPort(GetWindowPort(pMacWnd));
  281.  
  282.     return pMacWnd;
  283. }
  284.  
  285. Boolean IsQuickTimeInstalled(void) 
  286. {
  287.     OSErr    err;
  288.     long    lResult;
  289.  
  290.     err = Gestalt(gestaltQuickTime, &lResult);
  291.     return (err == noErr);
  292. }
  293.  
  294. void main(void)
  295. {
  296.     WindowRef                pMacWnd;
  297.     CGrafPtr                pTempPort;
  298.     SeqGrabComponent        seqGrab;
  299.     SGChannel                sgchanVideo, sgchanSound;
  300.     Rect                    thePortRect;
  301.     Boolean                    bDone = false;
  302.     
  303.     OSErr                    err = noErr;
  304.  
  305.     // initialize for carbon & QuickTime
  306.     InitCursor();
  307.     if ( IsQuickTimeInstalled() )
  308.         EnterMovies();
  309.     else
  310.         goto bail;
  311.         
  312.     GetQDGlobalsScreenBits( &screenBits );
  313.     
  314.     // create a window
  315.     pMacWnd = MakeAWindow();
  316.     
  317.     // create a sequence grabber
  318.     seqGrab = MakeSequenceGrabber(pMacWnd);
  319.     if (seqGrab == NULL)
  320.         return;
  321.  
  322.     // create the grab channels
  323.     GetPortBounds(GetWindowPort(pMacWnd), &thePortRect);
  324.     MakeSequenceGrabChannels(seqGrab, &sgchanVideo, &sgchanSound, &thePortRect, true); // true = recording
  325.     
  326.     // set up a video bottleneck
  327.     // create a temporary port for drawing...
  328.     pTempPort = CreateNewPort();                 
  329.     if (sgchanVideo != NULL) {
  330.         err = SetupVideoBottlenecks(sgchanVideo, pTempPort);
  331.     }
  332.     
  333.     // start the sequence grabber preview
  334.     err = SGStartPreview(seqGrab);
  335.  
  336.     while (!bDone) {
  337.         short        nPart;
  338.         WindowRef    pWhichWnd;
  339.         EventRecord    er; 
  340.  
  341.         GetNextEvent(everyEvent, &er);
  342.  
  343.         switch (er.what) {
  344.         case nullEvent:
  345.             // give the sequence grabber time                    
  346.             err = SGIdle(seqGrab);
  347.             if (err != noErr)
  348.                 bDone = true;
  349.             break;
  350.  
  351.         case updateEvt:
  352.             if (er.message == (long)pMacWnd) {
  353.                 RgnHandle updateRgn = NewRgn();
  354.                 
  355.                 GetWindowRegion(pMacWnd, kWindowUpdateRgn, updateRgn);
  356.                 
  357.                 // inform the sequence grabber of the update
  358.                 SGUpdate(seqGrab,updateRgn);
  359.                 
  360.                 // and swallow the update event
  361.                 BeginUpdate(pMacWnd);
  362.                 EndUpdate(pMacWnd);
  363.                 
  364.                 DisposeRgn(updateRgn);
  365.             }
  366.             break;
  367.  
  368.         case mouseDown:
  369.             nPart = FindWindow(er.where, &pWhichWnd);
  370.             if (pWhichWnd == pMacWnd) {
  371.                 switch (nPart) {
  372.                 case inContent:
  373.                     if ( er.modifiers & cmdKey ) {
  374.                         DoRecord( seqGrab );
  375.                         break;
  376.                     }
  377.                     
  378.                     // pause until mouse button is released
  379.                     SGPause(seqGrab, true);
  380.                     while (StillDown())
  381.                         ;
  382.                     SGPause(seqGrab, false);
  383.                     break;
  384.                 
  385.                 case inGoAway:
  386.                     bDone = TrackGoAway(pMacWnd, er.where);
  387.                     break;
  388.  
  389.                 case inDrag:
  390.                     if (StillDown()) {                    
  391.                         // pause when dragging window so video 
  392.                         // doesn't draw in the wrong place
  393.                         SGPause(seqGrab, true);
  394.                         DragAlignedWindow(pMacWnd, er.where, &screenBits.bounds, NULL, &apr);
  395.                         SGPause(seqGrab, false);
  396.                     }
  397.                     break;
  398.                 
  399.                 } // switch
  400.             }
  401.             break;
  402.             
  403.         } // switch
  404.     } // while
  405.     
  406. bail:
  407.  
  408.     // clean up
  409.     if ( seqGrab ) {
  410.         SGStop(seqGrab);
  411.         CloseComponent(seqGrab);
  412.     }
  413.     if ( pMacWnd )
  414.         DisposeWindow(pMacWnd);
  415. }